package com.sumainfor.common.wechat;

import com.sumainfor.common.util.FieldCheckUtil;
import com.sumainfor.common.utlis.AuthUtil;
import com.sumainfor.common.utlis.ComUtils;
import com.sumainfor.common.utlis.CompuUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.MessageDigest;
import java.util.*;
import java.util.Map.Entry;

/**
 * 功能描述:
 *
 * @Auther: zhlu
 * @Date: 2019/1/25 12:06
 * @Description:
 */
public class WxEncodeUtil {

    //生成网页二维码授权链接
    public static String getQrConnectURL(Map<String, String> params) {
        String wechat = "";
        if (!FieldCheckUtil.isMapFieldNotNull(params, new String[]{"appid"})) {
            wechat = null;
        } else if (!FieldCheckUtil.isMapFieldNotNull(params, new String[]{"redirect_uri"})) {
            wechat = null;
        } else if (!FieldCheckUtil.isMapFieldNotNull(params, new String[]{"response_type"})) {
            wechat = null;
        } else if (!FieldCheckUtil.isMapFieldNotNull(params, new String[]{"scope"})) {
            wechat = null;
        }
        if (!FieldCheckUtil.isMapFieldNotNull(params, new String[]{"state"})) {
            params.put("state", nonceStr() + "#wechat_redirect");
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> m : params.entrySet()) {
            sb.append(m.getKey().toString() + "=" + m.getValue().toString() + "&");
        }
        wechat = WxConstant.WECHATPAY_QRCONNECT_URL + "?" + sb.substring(0);
        return wechat;
    }

    /**
     * 获取微信支付时的32位加密随机数
     *
     * @return
     */
    public static String nonceStr() {
        String template = "abcdefghijklmnopqrstuvwxyz0123456789";
        StringBuffer buffer = new StringBuffer();
        Random random = new Random();
        while (buffer.length() < 32) {
            int index = random.nextInt(36);
            char c = template.charAt(index);
            buffer.append(c);
        }
        return MD5Encode(buffer.toString(), "utf8");
    }


    /**
     * 微信支付第一次加密签名 后返回加密后的sign
     *
     * @param map
     * @return
     */
    public static String signMd(TreeMap<String, String> map) {
        StringBuffer sb = new StringBuffer();
        Iterator<Entry<String, String>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, String> entry = it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append(k + "=" + v + "&");
        }
        String params = sb.append("key=" + WxConstant.WECHATPAY_KEY).substring(0);
        String sign = MD5Encode(params, "utf8");
        System.out.println("签名参数：" + params);
        return sign;
    }

    /**
     * 微信支付第二次加密签名
     *
     * @param map
     * @return
     */
    public static TreeMap<String, Object> signMdAgain(HashMap<String, Object> map) {
        //treeMap会自动按照ASCII 码从小到大排序（字典序）
        TreeMap<String, Object> tm = new TreeMap<String, Object>();
        StringBuffer sb = new StringBuffer();
        List<String> keys = new ArrayList<String>(map.keySet());
        Iterator<Entry<String, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, Object> entry = it.next();
            for (int i = 0; i < keys.size(); i++) {
                if (keys.get(i).equals(entry.getKey())) {
                    tm.put(keys.get(i), entry.getValue());

                }
            }
        }
        //将map合成字符串
        Iterator<Entry<String, Object>> its = tm.entrySet().iterator();
        while (its.hasNext()) {
            Entry<String, Object> entrys = its.next();
            String k = (String) entrys.getKey();
            Object v = (Object) entrys.getValue();
            sb.append(k + "=" + v + "&");
        }
        String params = sb.append("key=" + WxConstant.WECHATPAY_KEY).substring(0);
        //加密
        String sign = MD5Encode(params, "utf8");
        tm.put("sign", sign);

//	        System.out.println("sign拼接字符："+params);
        return tm;
    }


    /**
     * 获取时间戳 换算成秒
     *
     * @return
     */
    public static String getTimeStamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /**
     * 生成md5
     *
     * @param message
     * @return
     */
    public static String getMD5(String message) {
        String md5str = "";
        try {
            // 1 创建一个提供信息摘要算法的对象，初始化为md5算法对象
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 2 将消息变成byte数组
            byte[] input = message.getBytes();

            // 3 计算后获得字节数组,这就是那128位了
            byte[] buff = md.digest(input);

            // 4 把数组每一字节（一个字节占八位）换成16进制连成md5字符串
            md5str = bytesToHex(buff);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5str;
    }

    /**
     * 二进制转十六进制
     *
     * @param bytes
     * @return
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuffer md5str = new StringBuffer();
        // 把数组每一字节换成16进制连成md5字符串
        int digital;
        for (int i = 0; i < bytes.length; i++) {
            digital = bytes[i];

            if (digital < 0) {
                digital += 256;
            }
            if (digital < 16) {
                md5str.append("0");
            }
            md5str.append(Integer.toHexString(digital));
        }
        return md5str.toString().toUpperCase();
    }


    /**
     * 签名MD5加密
     *
     * @param origin
     * @param charsetname
     * @return
     */
    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};


    /**
     * 功能描述:
     * 微信支付发起的资料
     * body       商品描述
     * detail     商品详情
     * ServeType  支付模式      1.服务商模式   2.普通商户 普通商户没有父商户号
     * SubMchId   父商户号
     * MchId      当前商户号
     * payord     商户订单号
     * amount     标价金额
     * remoteIp   用户IP
     * uopid      用户openID
     * AppSecret  微信AppSecret
     * @Author zhlu
     * @Description //TODO
     * @Date 2019/3/24 12:35
     */
    public static Map<String, Object> WechatSign(Map<String, Object> params) throws Exception {
        TreeMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("appid", WeChatConfig.APP_ID);//公众账号ID
        parameters.put("body", params.get("body").toString());//商品描述
        parameters.put("detail", params.get("detail").toString());//商品详情
        //只有服务商模式才有子商户号
        if (params.get("ServeType").equals(1) || params.get("ServeType").toString() == "1") {
            parameters.put("mch_id", params.get("SubMchId").toString());//商户号
            parameters.put("sub_mch_id", params.get("MchId").toString());//子商户号
        } else {
            parameters.put("mch_id", params.get("MchId").toString());//商户号
        }

        parameters.put("nonce_str", ComUtils.randomUID());//随机字符串
        parameters.put("out_trade_no", params.get("payord").toString());//商户订单号
        //金额
        double amount = Double.valueOf(params.get("amount").toString());
//        parameters.put("total_fee",String.valueOf(amount));//标价金额
        parameters.put("total_fee", "1");//标价金额,一毛钱
        parameters.put("spbill_create_ip", params.get("remoteIp").toString());//用户IP
        parameters.put("notify_url", WeChatConfig.NOTIFY_URL);//微信支付通知url
        parameters.put("trade_type", WeChatConfig.TRADE_TYPE_JSAPI);//微信交易类型:公众号支付
        parameters.put("openid", params.get("uopid").toString());//用户openID
        String sign = WxEncodeUtil.signMd(parameters);
        parameters.put("sign", sign);
        String xml = RequestUtil.toXml(parameters);
        String results = RequestUtil.postXml(WeChatConfig.UNIFIED_ORDER_URL, xml);
        System.out.println(results);
        TreeMap<String, Object> wt = new TreeMap<>();
        //服务商模式传父商户号，普通商户传当前商户号
        if (params.get("ServeType").equals(1) || params.get("ServeType").toString() == "1") {
            wt = WxXmlUtil.toMap(results, params.get("SubMchId").toString());//获取返回结果集后做二次签名
        } else {
            wt = WxXmlUtil.toMap(results, params.get("MchId").toString());//获取返回结果集后做二次签名
        }

        System.out.println(wt);
        String returnCode = wt.get("return_code").toString();//通信标识
        String resultCode = wt.get("result_code").toString();//交易标识

        Map<String, Object> remap = new HashMap<String, Object>();

        if (WeChatConstant.RETURN_SUCCESS.equals(resultCode) && WeChatConstant.RETURN_SUCCESS.equals(returnCode)) {
            String appId = wt.get("appid").toString();//微信公众号AppId
            String prepayId = "prepay_id=" + wt.get("prepay_id");//统一下单返回的预支付id
            String timeStamp = wt.get("timestamp").toString();//当前时间戳
            String nonceStr = AuthUtil.getRandomStr(20);
            SortedMap<String, Object> signMap = new TreeMap();//自然升序map
            signMap.put("appId", appId);
            signMap.put("package", prepayId);
            signMap.put("timeStamp", timeStamp);
            signMap.put("nonceStr", nonceStr);
            signMap.put("signType", "MD5");

            remap.put("appId", appId);
            remap.put("timeStamp", timeStamp);
            remap.put("nonceStr", nonceStr);
            remap.put("prepayId", prepayId);
            remap.put("sign", sign);
            remap.put("paySign", AuthUtil.createSign("UTF-8", signMap, params.get("AppSecret").toString()));//获取签名
        }

        return remap;
    }

    /**
     * 功能描述:
     * 查询微信订单
     * ServeType  支付模式      1.服务商模式   2.普通商户 普通商户没有父商户号
     * SubMchId   父商户号
     * MchId      当前商户号
     * payord     商户订单号
     * @Author zhlu
     * @Description //TODO
     * @Date 2019/3/27 10:29
     */
    public static Map<String, Object> wechatOrderQuery(Map<String, Object> params) throws Exception {
        Map<String, Object> result = new HashMap<String, Object>();
        TreeMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("appid", WeChatConfig.APP_ID);// 公众账号ID

        //只有服务商模式才有子商户号
        if (params.get("ServeType").equals(1) || params.get("ServeType").toString() == "1") {
            parameters.put("mch_id", params.get("SubMchId").toString());//商户号
            parameters.put("sub_mch_id", params.get("MchId").toString());//子商户号
        } else {
            parameters.put("mch_id", params.get("MchId").toString());//商户号
        }

        parameters.put("out_trade_no", params.get("payord").toString());// 商户订单号
        parameters.put("nonce_str",ComUtils.randomUID());// 随机字符串
        parameters.put("sign_type", "MD5");// 签名类型
        String sign = WxEncodeUtil.signMd(parameters);
        parameters.put("sign", sign);
        String xml = RequestUtil.toXml(parameters);

        String results = RequestUtil.postXml(
                WeChatConfig.UNIFIED_ORDERQUERY_URL, xml);
        Map<String, String> map = WxXmlUtil.doXMLParse(results);
        HashMap<String, Object> hm = new HashMap<String, Object>();
        Iterator<Entry<String, String>> it = map.entrySet().iterator();
        String returnCode = "";// 通信标识
        String resultCode = "";// 业务标识
        String stateCode = "";// 交易标识
        while (it.hasNext()) {
            Entry<String, String> entry = it.next();
            if ("return_code".equals(entry.getKey()))// 返回状态码
                returnCode = entry.getValue();
            hm.put("return_code", entry.getValue());
            if ("result_code".equals(entry.getKey()))// 业务结果
                resultCode = entry.getValue();
            hm.put("result_code", entry.getValue());
            if ("is_subscribe".equals(entry.getKey()))// 是否关注公众账号
                hm.put("is_subscribe", entry.getValue());
            if ("trade_state".equals(entry.getKey()))// 交易状态
                stateCode = entry.getValue();
            hm.put("trade_state", entry.getValue());
            if ("trade_state_desc".equals(entry.getKey()))// 交易状态描述
                hm.put("trade_state_desc", entry.getValue());
            if ("total_fee".equals(entry.getKey()))// 标价金额
                hm.put("total_fee", entry.getValue());
            if ("transaction_id".equals(entry.getKey()))// 微信支付订单号
                hm.put("transaction_id", entry.getValue());
            if ("time_end".equals(entry.getKey()))// 支付完成时间
                hm.put("time_end", entry.getValue());
        }

        if (WeChatConstant.RETURN_SUCCESS.equals(returnCode)
                && WeChatConstant.RETURN_SUCCESS.equals(resultCode)
                && WeChatConstant.RETURN_SUCCESS.equals(stateCode)) {
            result.put("messageCode","0");
            result.put("messageStr","SUCCESS");
            result.putAll(hm);
        } else {//错误就返回错误的资料
            result.put("messageCode","400");
            result.put("messageStr", hm.get("trade_state_desc").toString());
        }
        return result;
    }


}
